  package com.tfj.widget;

  import android.content.Context;
  import android.graphics.Canvas;
  import android.graphics.Color;
  import android.graphics.CornerPathEffect;
  import android.graphics.Paint;
  import android.graphics.Path;
  import android.graphics.PixelFormat;
  import android.graphics.PorterDuffXfermode;
  import android.util.AttributeSet;
  import android.util.Log;
  import android.view.SurfaceHolder;
  import android.view.SurfaceView;
  import android.view.View;

  ;

  /**
   * 仿守望先锋的loading加载
   * Created by zhangyu on 2016/11/28.
   */

  public class OWLoadingView extends SurfaceView {
      private static final String TAG = "OWLoadingView";
      //view的宽度和高度
      private int viewWidth, viewHeight;
      //view的中心点
      private Point center = new Point();
      //六边形的中心点
      private Point[] hexagonCenters = new Point[6];
      //六边形实例
      private Hexagon[] hexagons = new Hexagon[7];
      //六边形之间的间距
      private float space;
      //六边形的半径
      private float hexagonRadius;
      private int color = Color.parseColor("#ff9900");//默认橙色
      private Paint paint;
      private float sin30 = (float) Math.sin(30f * 2f * Math.PI / 360f);
      private float cos30 = (float) Math.cos(30f * 2f * Math.PI / 360f);
      //进行显示动画和进行隐藏动画的标志常量
      private final int ShowAnimatorFlag = 0x1137, HideAnimatorFlag = 0x1139;
      private int nowAnimatorFlag = ShowAnimatorFlag;
      //触发下一个动画开始的缩放临界点值
      private final float scaleCritical = 0.7f;
      //控制动画运行的标示位
      private boolean runAnim = false;
      private SurfaceHolder surfaceHolder;
      //基准数据是否已初始化
      private boolean baseDataInited = false;
      //是否自动开始动画
      private boolean autoStartAnim = false;

      public OWLoadingView(Context context) {
          super(context);
          init();
      }

      public OWLoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
          super(context, attrs, defStyleAttr);
          init();
      }

      public OWLoadingView(Context context, AttributeSet attrs) {
          super(context, attrs);
          init();

      }

      private void init() {
          surfaceHolder = getHolder();
          setZOrderOnTop(true);
          surfaceHolder.setFormat(PixelFormat.TRANSLUCENT);//背景透明
          initPaint();
      }

      /**
       * 绘制图案
       */
      private void draw() {
          Canvas canvas = surfaceHolder.lockCanvas();
          if(canvas == null)
              return;
          paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.CLEAR));
          canvas.drawPaint(paint);
          paint.setXfermode(new PorterDuffXfermode(android.graphics.PorterDuff.Mode.DST_OVER));

          for (int i = 0; i < 7; i++) {
              hexagons[i].drawHexagon(canvas, paint);
          }
          surfaceHolder.unlockCanvasAndPost(canvas);
      }

      private Runnable animRunnable = new Runnable() {
          @Override
          public void run() {
              try {
                  while (runAnim) {
                      Thread.sleep(2);
                      flush();
                      draw();
                  }
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      };

      //重置六边形数据
      private void resetHexagons() {
          for (int i = 0; i < hexagons.length; i++) {
              hexagons[i].setScale(0);
              hexagons[i].setAlpha(0);
          }
      }

      private void initPaint() {
          paint = new Paint();
          paint.setAntiAlias(true);
          paint.setStyle(Paint.Style.FILL);
          paint.setColor(color);
      }

      /**
       * 设置颜色
       *
       * @param color
       */
      public void setColor(int color) {
          this.color = color;
          paint.setColor(color);
      }

      /**
       * 开始动画
       *
       * @return 动画是否启动成功，true 启动成功;false 启动失败
       */
      public boolean startAnim() {
          if (runAnim || !baseDataInited)
              return false;
          runAnim = true;
          new Thread(animRunnable).start();
          setVisibility(View.VISIBLE);
          return true;
      }

      /**
       * 中止动画
       */
      public void stopAnim() {
          runAnim = false;
          nowAnimatorFlag = ShowAnimatorFlag;
          resetHexagons();
          draw();
          setVisibility(View.GONE);
      }

      /**
       * 设置初始化完成后是否自动开始动画。
       * 如果开启，建议在页面onStop()时调用{@link #stopAnim}()方法中止动画，节约内存开销
       * @param autoStartAnim
       */
      public void setAutoStartAnim(boolean autoStartAnim) {
          this.autoStartAnim = autoStartAnim;
      }

      /**
       * 初始化六边形中心店坐标
       */
      private void initHexagonCenters() {
          //1.5*r 加上竖直方向space 等于R*cos30(博客里画的图是不匹配的)
          float bigR = (float) ((1.5 * hexagonRadius + space) / cos30);
          hexagonCenters[0] = new Point(center.x - bigR * sin30, center.y - bigR * cos30);
          hexagonCenters[1] = new Point(center.x + bigR * sin30, center.y - bigR * cos30);
          hexagonCenters[2] = new Point(center.x + bigR, center.y);
          hexagonCenters[3] = new Point(center.x + bigR * sin30, center.y + bigR * cos30);
          hexagonCenters[4] = new Point(center.x - bigR * sin30, center.y + bigR * cos30);
          hexagonCenters[5] = new Point(center.x - bigR, center.y);

          for (int i = 0; i < 6; i++) {
              hexagons[i] = new Hexagon(hexagonCenters[i], hexagonRadius);
          }
          hexagons[6] = new Hexagon(center, hexagonRadius);
      }

      @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
          super.onMeasure(widthMeasureSpec, heightMeasureSpec);
          viewHeight = getMeasuredHeight();
          viewWidth = getMeasuredWidth();
          if (viewWidth != 0 && viewHeight != 0) {
              center.x = viewWidth / 2f;
              center.y = viewHeight / 2f;
              float spaceRate = 1 / 100f;
              space = viewWidth <= viewHeight ? viewWidth * spaceRate : viewHeight * spaceRate;
              hexagonRadius = (float) ((viewWidth - 2 * space) / (3 * Math.sqrt(3)));
              initHexagonCenters();
              //圆角处理
              paint.setPathEffect(new CornerPathEffect(hexagonRadius * 0.1f));
              baseDataInited = true;
          }
      }

      /**
       * 刷新数据
       */
      private void flush() {
          if (nowAnimatorFlag == ShowAnimatorFlag) {//逐个显示出来
              hexagons[0].addScale();
              hexagons[0].addAlpha();
              for (int i = 0; i < hexagons.length - 1; i++) {
                  if (hexagons[i].getScale() >= scaleCritical) {
                      hexagons[i + 1].addScale();
                      hexagons[i + 1].addAlpha();
                  }
              }

              if (hexagons[6].getScale() == 1) {//当最后一个六边形都完全显示时，切换模式，下一轮逐个消失
                  nowAnimatorFlag = HideAnimatorFlag;
              }

          } else {//逐个消失
              hexagons[0].subScale();
              hexagons[0].subAlpha();
              for (int i = 0; i < hexagons.length - 1; i++) {
                  if (hexagons[i].getScale() <= 1 - scaleCritical) {
                      hexagons[i + 1].subScale();
                      hexagons[i + 1].subAlpha();
                  }
              }
              if (hexagons[6].getScale() == 0) {//当最后一个六边形都完全消失时，切换模式，下一轮逐个开始显示
                  nowAnimatorFlag = ShowAnimatorFlag;
              }
          }
      }

      /**
       * 六边形
       */
      private class Hexagon {

          //缩放值
          private float scale = 0;
          //透明度
          private int alpha = 0;
          public Point centerPoint;
          public float radius;
          //六个顶点
          private Point[] vertexs = new Point[6];
          //缩放程度每次改变量 变化范围为[0,1]
          private final float scaleChange = 0.07f;
          //透明度每次改变量 变化范围为[0,255]
          private final int alpahChange = 18;

          public Hexagon(Point centerPoint, float radius) {
              this.centerPoint = centerPoint;
              this.radius = radius;
              calculatePointsPosition();
          }

          public void drawHexagon(Canvas canvas, Paint paint) {
              paint.setAlpha(alpha);
              canvas.drawPath(getPath(), paint);
          }

          private int calculatePointsPosition() {
              if (centerPoint == null) {
                  return -1;
              }
              //从最上方顺时针数1-6给各顶点标序号 共6个点
              vertexs[0] = new Point(centerPoint.x, centerPoint.y - radius * scale);
              vertexs[1] = new Point(centerPoint.x + radius * cos30 * scale, centerPoint.y - radius * sin30 * scale);
              vertexs[2] = new Point(centerPoint.x + radius * cos30 * scale, centerPoint.y + radius * sin30 * scale);
              vertexs[3] = new Point(centerPoint.x, centerPoint.y + radius * scale);
              vertexs[4] = new Point(centerPoint.x - radius * cos30 * scale, centerPoint.y + radius * sin30 * scale);
              vertexs[5] = new Point(centerPoint.x - radius * cos30 * scale, centerPoint.y - radius * sin30 * scale);
              return 1;
          }


          private Path getPath() {
              Path path = new Path();
              for (int i = 0; i < 6; i++) {
                  if (i == 0)
                      path.moveTo(vertexs[i].x, vertexs[i].y);
                  else
                      path.lineTo(vertexs[i].x, vertexs[i].y);
              }
              path.close();
              return path;
          }

          /**
           * 设置透明度
           *
           * @param alpha
           */
          public void setAlpha(int alpha) {
              this.alpha = alpha;
          }

          public int getAlpha() {
              return alpha;
          }


          /**
           * 设置缩放比例
           *
           * @param scale
           */
          public void setScale(float scale) {
              this.scale = scale;
              calculatePointsPosition();
          }

          public void addScale() {
              if (scale == 1)
                  return;

              scale += scaleChange;
              scale = scale > 1 ? 1 : scale;
              calculatePointsPosition();
          }

          public void subScale() {
              if (scale == 0) {
                  return;
              }
              scale -= scaleChange;
              scale = scale < 0 ? 0 : scale;
              calculatePointsPosition();
          }

          public void addAlpha() {
              if (alpha == 255) {
                  return;
              }
              alpha += alpahChange;
              alpha = alpha > 255 ? 255 : alpha;
          }

          public void subAlpha() {
              if (alpha == 0) {
                  return;
              }
              alpha -= alpahChange;
              alpha = alpha < 0 ? 0 : alpha;
          }

          /**
           * 获取当前缩放比例
           *
           * @return
           */
          public float getScale() {
              return scale;
          }
      }

      private class Point {
          public float x, y;

          public Point(float x, float y) {
              this.x = x;
              this.y = y;
          }

          public Point() {
          }
      }

      @Override
      public void onWindowFocusChanged(boolean hasWindowFocus) {
          super.onWindowFocusChanged(hasWindowFocus);
          Log.d(TAG,"onWindowFocusChanged  "+hasWindowFocus);
          if(hasWindowFocus && autoStartAnim){
              startAnim();
          }
      }

  }
